/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
    AnnotationUsageIr,
    ArrowFunctionExpression,
    AssignmentExpression,
    BinaryExpression,
    BlockStatement,
    CallExpression,
    ClassDeclaration,
    ClassDefinition,
    ClassProperty,
    ClassStaticBlock,
    ETSFunctionType,
    EtsImportDeclaration,
    ETSParameterExpression,
    ETSPrimitiveType,
    EtsScript,
    ETSTypeReference,
    ETSTypeReferencePart,
    ETSUndefinedType,
    ETSUnionType,
    ExpressionStatement,
    FunctionDeclaration,
    FunctionExpression,
    Identifier,
    IfStatement,
    ImportSpecifier,
    MethodDefinition,
    NumberLiteral,
    ReturnStatement,
    ScriptFunction,
    StringLiteral,
    StructDeclaration,
    SuperExpression,
    TSTypeParameter,
    TSTypeParameterDeclaration,
    UndefinedLiteral,
    UnsupportedNode,
    VariableDeclaration,
    VariableDeclarator
} from "./types"
import { Es2pandaAstNodeType } from "../Es2pandaEnums"
import { MemberExpression } from "./to-be-generated/MemberExpression"
import { throwError } from "../utils"
import { global } from "./static/global"
import { KNativePointer, nullptr } from "@koalaui/interop"
import { AstNode } from "./peers/AstNode"
import { nodes as generatedNodes } from "../generated/node-map"

export function classByPeer(peer: KNativePointer): AstNode {
    const nodes = new Map<Es2pandaAstNodeType, { new(peer: KNativePointer): AstNode }>([
        [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_MODULE, EtsScript],
        [Es2pandaAstNodeType.AST_NODE_TYPE_IDENTIFIER, Identifier],
        [Es2pandaAstNodeType.AST_NODE_TYPE_STRING_LITERAL, StringLiteral],
        [Es2pandaAstNodeType.AST_NODE_TYPE_NUMBER_LITERAL, NumberLiteral],
        [Es2pandaAstNodeType.AST_NODE_TYPE_EXPRESSION_STATEMENT, ExpressionStatement],
        [Es2pandaAstNodeType.AST_NODE_TYPE_FUNCTION_DECLARATION, FunctionDeclaration],
        [Es2pandaAstNodeType.AST_NODE_TYPE_SCRIPT_FUNCTION, ScriptFunction],
        [Es2pandaAstNodeType.AST_NODE_TYPE_BLOCK_STATEMENT, BlockStatement],
        [Es2pandaAstNodeType.AST_NODE_TYPE_RETURN_STATEMENT, ReturnStatement],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_PARAMETER_EXPRESSION, ETSParameterExpression],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_TYPE_REFERENCE, ETSTypeReference],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_TYPE_REFERENCE_PART, ETSTypeReferencePart],
        [Es2pandaAstNodeType.AST_NODE_TYPE_TS_TYPE_PARAMETER_DECLARATION, TSTypeParameterDeclaration],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_PRIMITIVE_TYPE, ETSPrimitiveType],
        [Es2pandaAstNodeType.AST_NODE_TYPE_CALL_EXPRESSION, CallExpression],
        [Es2pandaAstNodeType.AST_NODE_TYPE_MEMBER_EXPRESSION, MemberExpression],
        [Es2pandaAstNodeType.AST_NODE_TYPE_TS_TYPE_PARAMETER, TSTypeParameter],
        [Es2pandaAstNodeType.AST_NODE_TYPE_IF_STATEMENT, IfStatement],
        [Es2pandaAstNodeType.AST_NODE_TYPE_BINARY_EXPRESSION, BinaryExpression],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_UNION_TYPE, ETSUnionType],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ARROW_FUNCTION_EXPRESSION, ArrowFunctionExpression],
        [Es2pandaAstNodeType.AST_NODE_TYPE_STRUCT_DECLARATION, StructDeclaration],
        [Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DECLARATION, ClassDeclaration],
        [Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DEFINITION, ClassDefinition],
        [Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, MethodDefinition],
        [Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, ClassProperty],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ASSIGNMENT_EXPRESSION, AssignmentExpression],
        [Es2pandaAstNodeType.AST_NODE_TYPE_VARIABLE_DECLARATION, VariableDeclaration],
        [Es2pandaAstNodeType.AST_NODE_TYPE_VARIABLE_DECLARATOR, VariableDeclarator],
        [Es2pandaAstNodeType.AST_NODE_TYPE_FUNCTION_EXPRESSION, FunctionExpression],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_FUNCTION_TYPE, ETSFunctionType],
        [Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_STATIC_BLOCK, ClassStaticBlock],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_UNDEFINED_TYPE, ETSUndefinedType],
        [Es2pandaAstNodeType.AST_NODE_TYPE_UNDEFINED_LITERAL, UndefinedLiteral],
        [Es2pandaAstNodeType.AST_NODE_TYPE_SUPER_EXPRESSION, SuperExpression],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_IMPORT_DECLARATION, EtsImportDeclaration],
        [Es2pandaAstNodeType.AST_NODE_TYPE_IMPORT_SPECIFIER, ImportSpecifier],
        [Es2pandaAstNodeType.AST_NODE_TYPE_ANNOTATION_USAGE, AnnotationUsageIr],
    ])

    if (peer === nullptr) {
        throwError('classByPeer: peer is NULLPTR')
    }
    const type = global.generatedEs2panda._AstNodeTypeConst(global.context, peer)
    const node = nodes.get(type) ?? generatedNodes.get(type)
    if (node === undefined) {
        return new UnsupportedNode(peer)
    }
    return new node(peer)
}